package com.example.musicbox.service.impl;

import com.baomidou.mybatisplus.core.conditions.query.QueryWrapper;
import com.baomidou.mybatisplus.extension.plugins.pagination.Page;
import com.example.musicbox.config.MyException;
import com.example.musicbox.entity.MCatalogue;
import com.example.musicbox.entity.MMusic;
import com.example.musicbox.entity.MUser;
import com.example.musicbox.entity.MUserCatalogue;
import com.example.musicbox.enums.AboutMusic;
import com.example.musicbox.enums.LogDoType;
import com.example.musicbox.mapper.MCatalogueMapper;
import com.example.musicbox.mapper.MMusicMapper;
import com.example.musicbox.mapper.MUserCatalogueMapper;
import com.example.musicbox.mapper.MUserMapper;
import com.example.musicbox.service.MMusicService;
import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
import com.example.musicbox.utils.Result;
import org.springframework.data.redis.core.RedisTemplate;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;

import javax.annotation.Resource;
import java.util.List;

/**
 * <p>
 * 服务实现类
 * </p>
 *  声明：上传音乐之后，音乐就是我的，用户删除的只是他本人的数据库记录
 * @author 帅哥是我
 * @since 2022-08-01
 */
@Service
public class MMusicServiceImpl extends ServiceImpl<MMusicMapper, MMusic> implements MMusicService {

    @Resource
    private RedisTemplate redisTemplate;

    @Resource
    private MUserMapper mUserMapper;

    @Resource
    private MMusicMapper mMusicMapper;

    @Resource
    private MLogServiceImpl mLogService;

    @Resource
    private MMessageServiceImpl mMessageService;

    @Resource
    private MUListenServiceImpl muListenService;

    @Resource
    private MCatalogueMapper mCatalogueMapper;

    @Resource
    private MUserCatalogueMapper mUserCatalogueMapper;

    @Resource
    private FileOperationServiceImpl fileOperationService;

    /**
     * 用户上传音乐
     *
     * @param mMusic
     * @param token
     * @return
     */
    @Transactional
    @Override
    public Result insertMusic(MMusic mMusic, String token) {
        try {
            Integer userId = (Integer) redisTemplate.opsForValue().get(token);
            MUser mUser = mUserMapper.selectById(userId);
            mMusic.setUid(userId);
            QueryWrapper<MCatalogue> wrapper = new QueryWrapper<>();
            //0代表共有，需要管理员审核,到时候直接将审核状态改为0，代表已经审核完成
            if (mMusic.getIspublish().equals("0")) {
                mMusic.setMstatus("1");
                mMusicMapper.insert(mMusic);
                //添加到用户音乐目录关联表中
                wrapper.eq("cName","本地目录").eq("uId",userId);
                MCatalogue catalogue = mCatalogueMapper.selectOne(wrapper);
                MUserCatalogue mUserCatalogue = new MUserCatalogue();
                mUserCatalogue.setUid(userId);
                mUserCatalogue.setCid(catalogue.getMid());
                mUserCatalogue.setMid(mMusic.getMid());
                mUserCatalogueMapper.insert(mUserCatalogue);
                //发送消息
                mMessageService.sendMessage(userId, null, "0", null, mUser.getUsername(), mMusic.getMid(), token);
                //记录日志
                mLogService.insertLog("用户上传了一首歌曲", AboutMusic.UPLOADMUSIC, mMusic.getMid(), LogDoType.INSERT, token);
            } else if(mMusic.getIspublish().equals("1")){
                mMusicMapper.insert(mMusic);
                //添加到用户音乐目录关联表中
                wrapper.eq("cName","本地目录").eq("uId",userId);
                MCatalogue catalogue = mCatalogueMapper.selectOne(wrapper);
                MUserCatalogue mUserCatalogue = new MUserCatalogue();
                mUserCatalogue.setUid(userId);
                mUserCatalogue.setCid(catalogue.getMid());
                mUserCatalogue.setMid(mMusic.getMid());
                mUserCatalogueMapper.insert(mUserCatalogue);
                mLogService.insertLog("用户上传了一首歌曲", AboutMusic.UPLOADMUSIC, mMusic.getMid(), LogDoType.INSERT, token);
            }else {
                return Result.error("歌曲上传成功");
            }
        } catch (Exception e) {
            throw new MyException("新增音乐失败");
        }
        return Result.ok("歌曲上传成功");
    }


    /**
     * 逻辑：当音乐为私有的时候，用户删除音乐，音乐，音乐目录关系，云这三者都删除
     *       当音乐为共有，删除音乐直接删除用户的音乐目录关系表
     * @param id 音乐id
     * @param token
     * @return
     */
    @Override
    public Result deleteMusic(Integer id, String token) {
        try {
            Integer userId = (Integer) redisTemplate.opsForValue().get(token);
            MMusic mMusic = mMusicMapper.selectById(id);
            //说明这是一个私有的音乐
            if (mMusic.getIspublish().equals("1")) {
                //1删除云的文件
                fileOperationService.deleteFile(mMusic.getMurl(),token);
                if (mMusic.getMvurl() != null) {
                    fileOperationService.deleteFile(mMusic.getMvurl(),token);
                }
            }
            //2删除音乐列表
            mMusicMapper.deleteById(id);
            //3删除音乐用户目录关联表
            QueryWrapper<MUserCatalogue> wrapper = new QueryWrapper<>();
            wrapper.eq("mId", id).eq("uId", userId);
            mUserCatalogueMapper.delete(wrapper);
            //4 记录日志
            mLogService.insertLog("用户删除了音乐", AboutMusic.DELETEMUSIC, id, LogDoType.DELETE, token);
            return Result.ok("音乐删除成功");
        } catch (Exception e) {
            throw new MyException("歌曲删除失败");
        }
    }


    @Override
    public Result playMusic(Integer id, String token) {
        try {
            Integer userId = (Integer) redisTemplate.opsForValue().get(token);
            MMusic mMusic = mMusicMapper.selectById(id);
            MUser mUser = mUserMapper.selectById(userId);
            String ispublish = mMusic.getIspublish();
            Integer adminId = mUserMapper.findAdmin();
            // 超级管理员不需要听歌权限
            if (adminId.equals(userId)) {
                //歌曲总的听歌次数+1
                Integer listenCount = mMusic.getListencount();
                mMusic.setListencount(listenCount+1);
                mMusicMapper.updateById(mMusic);
                //用户听本歌记录+1
                muListenService.UserListenCount(id, userId);
                mLogService.insertLog("超级管理员在听歌", AboutMusic.LISTENMUSIC, mMusic.getMid(), LogDoType.CHECK, token);
                return Result.ok("超级管理员听音乐中").put("musicUrl",mMusic.getMurl());
            }
            //“1”代表私有,当音乐为私有和归属他本人的时候，用户可以直接播放
            if (ispublish.equals("1") && mMusic.getUid().equals(userId)) {
                //用户听本歌记录+1
                muListenService.UserListenCount(id, userId);
                //添加日志记录
                mLogService.insertLog("用户在听歌", AboutMusic.LISTENMUSIC, mMusic.getMid(), LogDoType.CHECK, token);
                return Result.ok("音乐正在加载中").put("musicUrl",mMusic.getMurl());
            }
            //如果是公有的，则看用户有没有这个权限
            else {
                Integer needlevel = mMusic.getNeedlevel();
                if (needlevel <= mUser.getViplevel()) {
                    //歌曲总的听歌次数+1
                    Integer listenCount = mMusic.getListencount();
                    mMusic.setListencount(listenCount+1);
                    mMusicMapper.updateById(mMusic);
                    //用户听本歌记录+1
                    muListenService.UserListenCount(id, userId);
                    //添加日志记录
                    mLogService.insertLog("用户在听歌", AboutMusic.LISTENMUSIC, mMusic.getMid(), LogDoType.CHECK, token);

                    return Result.ok("vip" + mUser.getViplevel() + "音乐正在加载中").put("musicUrl",mMusic.getMurl());
                } else {
                    return Result.error("请冲对应的会员，尽享会员福利！");
                }
            }

        } catch (Exception e) {
            throw new MyException("歌曲加载失败");
        }
    }

    /**
     * 用户收藏音乐直接将其添加到收藏营养的目录中，
     * 收藏音乐不一定都是可以播放的，但所有音乐都可以收藏
     * @param id 菜单id
     * @param token
     * @return
     */
    @Transactional
    @Override
    public Result fontMusic(Integer id, String token) {
        try {
            Integer userId = (Integer) redisTemplate.opsForValue().get(token);
            //查询用户收藏目录的id
            QueryWrapper<MCatalogue> wrapper = new QueryWrapper<>();
            wrapper.eq("uId", userId).eq("cName", "我的收藏");
            MCatalogue mCatalogue = mCatalogueMapper.selectOne(wrapper);
            Integer mid = mCatalogue.getMid();
            //将音乐添加到收藏列表中
            MUserCatalogue mUserCatalogue = new MUserCatalogue();
            mUserCatalogue.setCid(mid);
            mUserCatalogue.setMid(id);
            mUserCatalogue.setUid(userId);
            mUserCatalogueMapper.insert(mUserCatalogue);
            //添加日志记录
            mLogService.insertLog("用户添加音乐收藏",AboutMusic.FONTMUSIC,id,LogDoType.INSERT,token);
            return Result.ok("歌曲添加收藏成功");
        } catch (Exception e) {
            throw new MyException("添加收藏列表失败");
        }
    }


    /**
     * 分页查询所有公开的音乐
     * @param p
     * @param s
     * @return
     */
    @Override
    public Result selectAll(Integer p, Integer s) {
        try {
            QueryWrapper<MMusic> wrapper = new QueryWrapper<>();
            wrapper.eq("isPublish","0").eq("mStatus","0");
            Page<MMusic> musicPage = mMusicMapper.selectPage(new Page<>(p, s), wrapper);
            return Result.ok("查询成功").put("musicPage",musicPage);
        }catch (Exception e){
            throw new MyException("查询失败");
        }
    }


    /**
     * 根据歌曲名称模糊查询
     * 查询出的音乐为公开且审核通过
     * @param name
     * @param p
     * @param s
     * @return
     */
    @Override
    public Result selectByName(String name, Integer p, Integer s) {
        try {
            QueryWrapper<MMusic> wrapper = new QueryWrapper<>();
            wrapper.eq("isPublish","0").eq("mStatus","0").like("mName",name);
            Page<MMusic> musicPage = mMusicMapper.selectPage(new Page<>(p, s), wrapper);
            return Result.ok("查询成功").put("musicPage",musicPage);
        }catch (Exception e){
            throw new MyException("查询失败");
        }
    }


    /**
     * 根据音乐类型查询音乐
     * 查询的音乐必须为公有，而且审批通过
     * @param type
     * @param p
     * @param s
     * @return
     */
    @Override
    public Result selectByType(Integer type, Integer p, Integer s) {
        try {
            QueryWrapper<MMusic> wrapper = new QueryWrapper<>();
            wrapper.eq("isPublish","0").eq("mStatus","0").like("mType",type);
            Page<MMusic> musicPage = mMusicMapper.selectPage(new Page<>(p, s), wrapper);
            return Result.ok("查询成功").put("musicPage",musicPage);
        }catch (Exception e){
            throw new MyException("查询失败");
        }
    }


    /**
     * 逻辑
     * @param mId
     * @param token
     * @param path 下载存放的路径
     * @return
     */
    @Transactional
    @Override
    public Result downloadMusic(Integer mId, String path, String token) {
        try {
            Integer userId = (Integer) redisTemplate.opsForValue().get(token);
            MMusic mMusic = mMusicMapper.selectById(mId);
            MUser mUser = mUserMapper.selectById(userId);
            if (mMusic.getUid().equals(userId) || mMusic.getNeedlevel() <= mUser.getViplevel()) {
                fileOperationService.downloadFile(mMusic.getMurl(), path, token);
                Integer downloadCount = mMusic.getDownloadcount();
                mMusic.setDownloadcount(downloadCount+1);
                mMusicMapper.updateById(mMusic);
                return Result.ok("下载成功");
            } else {
                return Result.error("请冲会员");
            }
        } catch (Exception e) {
            throw new MyException("下载失败");
        }
    }


    /**
     * 为你智能推荐,不给白嫖，不传递音乐地址给用户
     * @param p
     * @param s
     * @return
     */
    @Override
    public Result recommendMusic(Integer p, Integer s) {
        try {
            QueryWrapper<MMusic> wrapper = new QueryWrapper<>();
            wrapper.eq("isPublish","0").eq("mStatus","0").orderByDesc("listenCount");
            Page<MMusic> mMusicPage = mMusicMapper.selectPage(new Page<>(p, s), wrapper);
            List<MMusic> records = mMusicPage.getRecords();
            records.stream().forEach(mMusic -> {
                mMusic.setMurl(null);
                mMusic.setMvurl(null);
            });
            mMusicPage.setRecords(records);
            return Result.ok("查询成功").put("mMusicPage",mMusicPage);
        }catch (Exception e){
            throw new MyException("无法为您匹配数据！");
        }
    }

}
